package com.atguigu.gmall.gateway.fiter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.IpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

@Component
public class AuthGlobalFilter implements GlobalFilter {

    @Value("${authUrls.url}")
    private String authUrls;

    @Autowired
    private RedisTemplate redisTemplate;

    private AntPathMatcher pathMatcher = new AntPathMatcher();

    /*
     exchange spring框架封装的 web 服务请求request与响应response对象
     chain 过滤器链对象
    */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //先获取到url路径
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        if (pathMatcher.match("/**/inner/**",path)){
            //设置响应
            ServerHttpResponse response = exchange.getResponse();
            //提示用户没有权限访问
            return out(response, ResultCodeEnum.PERMISSION);
        }
        //获取到登录的userId,在缓存中获取,必须要有token，token存储在header或者cookie
        String userId = this.getUserId(request);

        String userTempId = this.getUserTempId(request);
        //判断是否属于非法登录  redis中的ip与当前ip不相等 非法登录
        if ("-1".equals(userId)){
            //设置响应
            ServerHttpResponse response = exchange.getResponse();
            //提示用户没有权限访问
            return out(response, ResultCodeEnum.PERMISSION);
        }
        if (pathMatcher.match("/api/**/auth/**",path)){
            //判断用户是否登录，如果未登录提示登录
            if (StringUtils.isEmpty(userId)){
                //提示信息
                ServerHttpResponse response = exchange.getResponse();
                //提示用户未登录
                return out(response, ResultCodeEnum.LOGIN_AUTH);
            }
        }
        //用户在访问哪些业务层控制器时需要登陆  订单 购物车
        String[] split = authUrls.split(",");
        if (split!=null && split.length>0){
            for (String url : split) {
                //path包含上述控制器  并且Id为空，此时需要拦截并跳转
                if (path.indexOf(url)!=-1 && StringUtils.isEmpty(userId)){
                    //获取响应
                    ServerHttpResponse response = exchange.getResponse();
                    //设置参数
                    response.setStatusCode(HttpStatus.SEE_OTHER);
                    //重定向到登录页面
                    response.getHeaders().set(HttpHeaders.LOCATION,"http://www.gmall.com/login.html?originUrl="+request.getURI());
                    //重定向
                    return response.setComplete();
                }
            }
        }
        //将获取到的用户id添加到请求头 请求头可能会存在存有UserId   OOP思想
        if (!StringUtils.isEmpty(userId)||!StringUtils.isEmpty(userTempId)){
            if (!StringUtils.isEmpty(userId)){
                //放入请求头
                request.mutate().header("userId",userId).build();
            }
            if (!StringUtils.isEmpty(userTempId)){
                //放入请求头
                request.mutate().header("userTempId",userTempId).build();
            }
            return chain.filter(exchange.mutate().request(request).build());
        }

        //默认返回 表示这个过滤器结束了
        return chain.filter(exchange);
    }

    //获取临时用户Id
    private String getUserTempId(ServerHttpRequest request) {
        //可能存在cookie 或 header中
        String userTempId = "";
        HttpCookie httpCookie = request.getCookies().getFirst("userTempId");
        if (httpCookie!=null){
            userTempId = httpCookie.getValue();
        }else{
            List<String> stringList = request.getHeaders().get("userTempId");
            if (!CollectionUtils.isEmpty(stringList)){
                userTempId = stringList.get(0);
            }
        }
        return userTempId;
    }

    //获取用户Id
    private String getUserId(ServerHttpRequest request) {
        //设置一个token
        String token = "";
        //用户id可能存在cookie 或 header
        HttpCookie httpCookie = request.getCookies().getFirst("token");
        if (httpCookie!=null){
            token = httpCookie.getValue();
        }else{
            List<String> stringList = request.getHeaders().get("token");
            if (!CollectionUtils.isEmpty(stringList)){
                token = stringList.get(0);
            }
        }
        //判断token不为空
        if (!StringUtils.isEmpty(token)){
            //组成缓存的key
            String userLoginKey = "user:login:"+token;
            //从缓存中获取userId
            String strJson = (String) this.redisTemplate.opsForValue().get(userLoginKey);
            if (!StringUtils.isEmpty(strJson)){
                JSONObject jsonObject = JSON.parseObject(strJson);
                //判断当前缓存中的id与正在操作的客户端ip地址是否一致
                String ip = (String) jsonObject.get("ip");
                if (IpUtil.getGatwayIpAddress(request).equals(ip)){
                    String userId = (String) jsonObject.get("userId");
                    return userId;
                }else{
                    return "-1";
                }
            }
        }
        //默认返回"";
        return "";
    }

    //输出方法
    private Mono<Void> out(ServerHttpResponse response, ResultCodeEnum resultCodeEnum) {
        //输出内容
        //String message = resultCodeEnum.getMessage();
        Result result = Result.build(null,resultCodeEnum);
        //将这个result变成String
        String str = JSON.toJSONString(result);
        DataBuffer wrap = response.bufferFactory().wrap(str.getBytes());
        //设置请求头信息
        response.getHeaders().add("Content-Type","application/json;charset=UTF-8");
        //产生DataBuffer

        return response.writeWith(Mono.just(wrap));
    }
}
